ifeq ($(subdir),math)

#
# Only enable ifunc _Float128 support if the baseline cpu support
# is older than power9.
ifneq (yes,$(libc-submachine-power9))
do_f128_multiarch = yes
endif

#
# This is an ugly, but contained, mechanism to provide hardware optimized
# _Float128 and ldouble == ieee128 optimized routines for P9 and beyond
# hardware.  At a very high level, we rely on ASM renames, and rarely
# macro renames to build two sets of _Float128 ABI, one with _power8 (the
# baseline powerpc64le cpu) and _power9 (the first powerpc64le cpu to introduce
# hardware support for _Float128).
#
# At a high level, we compile 3 files for each object file.
#   1.  The baseline soft-float128, unsuffixed objects $(object).$(sfx)
#       The symbols contained in these files is suffixed by _power8.
#   2.  The hard-float128, power9, suffixed objects $(object)-power9.$(sfx).
#       The symbols contained in these files is suffixed by _power9.
#   3.  The IFUNC wrapper object to export ABI, $(object)-ifunc.$(sfx)
#       This glues the above together and implements the ABI.
#
# 2 & 3 are automatically generated by Makefile rule.  Placing the exported
# ABI into a separate file allows reuse of existing aliasing macros
# with minimal hassle.
#
#
# If the float128 ABI is expanded, and a new ifunc wrappers are desired,
# the following lists how to map new symbols from the shared headers into
# their local overrides here:
#
#   float128_private.h
#
#     is used to rename the ldouble == ieee128 object files.  This takes
#     it a step further and redirects symbols to a local name.  This supports
#     nearly all files in sysdeps/ieee754/float128, but not all _Float128
#     objects.  However, this is only meant to be used internally to support
#     compilation of ldbl-128 into float128.
#
#   math-type-macros-float128.h
#
#     renames symbols which are generated via shared templated in math/.
#
#   math_private.h
#
#     provides internal declarations for common macros and functions which
#     are called from within libm.  Note, float128_private.h duplicates
#     some of these declarations as these headers are generally not included
#     in the same translation unit.
#
# The above is supported by several header files as described below:
#
#   float128-ifunc.h
#
#     provides support for generating the IFUNC objects in part 3 above.
#     This header is only included with wrapper functions.
#
#   float128-ifunc-macros.h
#
#     disables all first-order float128 aliasing macros used in libm,
#     and libm wrappers around libc-symbols.h.
#
#   float128-ifunc-redirect-macros.h
#
#     provides macros which implement the appending of the suffix to
#     symbols what have been selected.
#
#   float128-ifunc-redirects.h
#
#     provides ASM redirects for symbols which are redirected in the
#     private copy of math.h used by glibc, but not declared by math_private.h
#
#   float128-ifunc-redirects-mp.h
#
#     provides ASM redirects which are used by math_private.h (the -mp suffix)
#     and the interposer float128_private.h discussed late.
#
# Notably, this enforces a slightly different mechanism for machine specific
# overrides.  Optimizations for all targets must all be reachable from the same
# file.  See the history to fmaf128 or sqrtf128 to understand how this looks
# in practice.
#
ifeq ($(do_f128_multiarch),yes)

f128-ifunc-calls = s_modff128 s_scalbnf128 s_frexpf128 s_ldexpf128
gen-libm-f128-ifunc-routines = \
	e_acosf128 e_acoshf128 e_asinf128 e_atan2f128 e_atanhf128 e_coshf128 \
	e_expf128 e_fmodf128 e_hypotf128 e_j0f128 e_j1f128 e_jnf128 \
	e_lgammaf128_r e_logf128 e_log10f128 e_powf128 e_remainderf128 \
	e_sinhf128 e_sqrtf128 e_gammaf128_r e_ilogbf128 k_tanf128 s_asinhf128 \
	s_atanf128 s_cbrtf128 s_ceilf128 s_cosf128 s_erff128 s_expm1f128 \
	s_fabsf128 s_floorf128 s_log1pf128 s_logbf128 \
	s_rintf128 s_scalblnf128 s_sinf128 s_tanf128 \
	s_tanhf128 s_truncf128 s_remquof128 e_log2f128 \
	s_roundf128 s_nearbyintf128 s_sincosf128 s_fmaf128 s_lrintf128 \
	s_llrintf128 s_lroundf128 s_llroundf128 e_exp10f128 \
	$(f128-ifunc-calls) $(f128-ifunc-calls:s_%=m_%) x2y2m1f128 \
	gamma_productf128 lgamma_negf128 lgamma_productf128 s_roundevenf128 \
	cargf128 conjf128 cimagf128 crealf128 cabsf128 e_scalbf128 s_cacosf128 \
	s_cacoshf128 s_ccosf128 s_ccoshf128 s_casinf128 s_csinf128 \
	s_casinhf128 k_casinhf128 s_csinhf128 k_casinhf128 s_csinhf128 \
	s_catanhf128 s_catanf128 s_ctanf128 s_ctanhf128 s_cexpf128 s_clogf128 \
	s_cprojf128 s_csqrtf128 s_cpowf128 s_clog10f128 s_fdimf128 \
	s_fmaxf128 s_fminf128 w_ilogbf128 w_llogbf128 \
	w_log1pf128 w_scalblnf128 w_acosf128 \
	w_acoshf128 w_asinf128 w_atan2f128 w_atanhf128 w_coshf128 w_exp10f128 \
	w_exp2f128 w_fmodf128 w_hypotf128 w_j0f128 w_j1f128 w_jnf128 \
	w_logf128 w_log10f128 w_log2f128 w_powf128 w_remainderf128 \
	w_scalbf128 w_sinhf128 w_sqrtf128 w_tgammaf128 w_lgammaf128 \
	w_lgammaf128_r w_expf128 e_exp2f128 \
	k_sinf128 k_cosf128 k_sincosf128 e_rem_pio2f128


f128-march-routines-p9 = $(addsuffix -power9,$(gen-libm-f128-ifunc-routines))
f128-march-routines-ifunc = $(addsuffix -ifunc,$(gen-libm-f128-ifunc-routines))
f128-march-routines = $(f128-march-routines-p9) $(f128-march-routines-ifunc)
f128-march-cpus = power9

f128-march-calls-p9 = $(addsuffix -power9,$(f128-ifunc-calls))
f128-march-calls-ifunc = $(addsuffix -ifunc,$(f128-ifunc-calls))
f128-march-calls = $(f128-march-calls-p9) $(f128-march-calls-ifunc)

calls += $(f128-march-calls)
libm-routines += $(filter-out $(f128-march-calls), $(f128-march-routines))
generated += $(f128-march-routines)

CFLAGS-float128-ifunc.c += $(type-float128-CFLAGS) $(no-gnu-attribute-CFLAGS)

# Copy special CFLAGS for some functions
CFLAGS-s_modff128-power9.c += $(config-cflags-signaling-nans)
CFLAGS-m_modff128-power9.c += $(config-cflags-signaling-nans)

# Generate ifunc wrapper files and target specific wrappers around
# each routine above.  Note, m_%.c files are fixed up to include
# s_%.c files.  This is an artifact of the makefile rules which allow
# some files to be compiled for libc and libm.
$(objpfx)gen-float128-ifuncs.stmp: \
  Makefile $(..)sysdeps/powerpc/powerpc64/le/fpu/multiarch/Makefile
	$(make-target-directory)
	for gcall in $(gen-libm-f128-ifunc-routines); do \
	  ifile="$${gcall}";                             \
	  if [ $${gcall##m_} != $${gcall} ]; then        \
	    ifile="s_$${gcall##m_}";                     \
	  fi;                                            \
	  for cpu in $(f128-march-cpus); do              \
	    file=$(objpfx)$${gcall}-$${cpu}.c;           \
	    {                                            \
	      echo "#include <$${ifile}.c>";             \
	    } > $${file};                                \
	  done;                                          \
	  name="$${gcall##?_}";                          \
	  pfx="$${gcall%%_*}";                           \
	  R="";                                          \
	  r="";                                          \
	  if [ $${gcall##m_} != $${gcall} ]; then        \
	    pfx="s";                                     \
	  fi;                                            \
	  if [ $${#pfx} != 1 ]; then                     \
	    pfx="";                                      \
	  else                                           \
	    pfx="_$${pfx}";                              \
	  fi;                                            \
	  if [ $${name%%_r} != $${name} ]; then          \
	    R="_R";                                      \
	    r="_r";                                      \
	    name="$${name%%_r}";                         \
	  fi;                                            \
	  name="$${name%%f128}";                         \
	  decl="DECL_ALIAS$${pfx}_$${name}$${r}";        \
	  compat="GEN_COMPAT$${pfx}_$${name}$${r}";      \
	  declc="DECL_ALIAS$${R}$${pfx}";                \
	  {                                              \
	    echo "#include <float128-ifunc.h>";          \
	    echo "#ifndef $${decl}";                     \
	    echo "# define $${decl}(f) $${declc} (f)";   \
	    echo "#endif";                               \
	    echo "#ifndef $${compat}";                   \
	    echo "# define $${compat}(f)";               \
	    echo "#endif";                               \
	    echo "$${decl} ($${name});";                 \
	    echo "$${compat} ($${name});";               \
	  } > $(objpfx)$${gcall}-ifunc.c;                \
	done;                                            \
	echo > $(@)

$(foreach f,$(f128-march-routines),$(objpfx)$(f).c): \
  $(objpfx)gen-float128-ifuncs.stmp $(objpfx)gen-libm-templates.stmp

enable-f128-ifunc-CFLAGS = -D_F128_ENABLE_IFUNC $(no-gnu-attributes-CFLAGS) $(type-float128-CFLAGS)

# Enable IFUNC on baseline (power8) implementations
include $(o-iterator)
define o-iterator-doit
$(foreach f,$(gen-libm-f128-ifunc-routines),$(objpfx)$(f)$(o)): sysdep-CFLAGS += -D_F128_ENABLE_IFUNC
endef
object-suffixes-left := $(all-object-suffixes)
include $(o-iterator)

# Likewise, but for power9.
include $(o-iterator)
define o-iterator-doit
$(foreach f,$(f128-march-routines-p9),$(objpfx)$(f)$(o)): sysdep-CFLAGS += $$(enable-f128-ifunc-CFLAGS) -mcpu=power9
endef
object-suffixes-left := $(all-object-suffixes)
include $(o-iterator)

CFLAGS-w_acosf128-ifunc.c += -fno-builtin-acosf64x
CFLAGS-w_acoshf128-ifunc.c += -fno-builtin-acoshf64x
CFLAGS-w_asinf128-ifunc.c += -fno-builtin-asinf64x
CFLAGS-s_asinhf128-ifunc.c += -fno-builtin-asinhf64x
CFLAGS-s_atanf128-ifunc.c += -fno-builtin-atanf64x
CFLAGS-w_atan2f128-ifunc.c += -fno-builtin-atan2f64x
CFLAGS-w_atanhf128-ifunc.c += -fno-builtin-atanhf64x
CFLAGS-s_cabsf128-ifunc.c += -fno-builtin-cabsf64x
CFLAGS-s_cacosf128-ifunc.c += -fno-builtin-cacosf64x
CFLAGS-s_cacoshf128-ifunc.c += -fno-builtin-cacoshf64x
CFLAGS-s_canonicalizef128-ifunc.c += -fno-builtin-canonicalizef64x
CFLAGS-s_cargf128-ifunc.c += -fno-builtin-cargf64x
CFLAGS-s_casinf128-ifunc.c += -fno-builtin-casinf64x
CFLAGS-s_casinhf128-ifunc.c += -fno-builtin-casinhf64x
CFLAGS-s_catanf128-ifunc.c += -fno-builtin-catanf64x
CFLAGS-s_catanhf128-ifunc.c += -fno-builtin-catanhf64x
CFLAGS-s_cbrtf128-ifunc.c += -fno-builtin-cbrtf64x
CFLAGS-s_ccosf128-ifunc.c += -fno-builtin-ccosf64x
CFLAGS-s_ccoshf128-ifunc.c += -fno-builtin-ccoshf64x
CFLAGS-s_ceilf128-ifunc.c += -fno-builtin-ceilf64x
CFLAGS-s_cexpf128-ifunc.c += -fno-builtin-cexpf64x
CFLAGS-s_cimagf128-ifunc.c += -fno-builtin-cimagf64x
CFLAGS-s_clogf128-ifunc.c += -fno-builtin-clogf64x
CFLAGS-s_clog10f128-ifunc.c += -fno-builtin-clog10f64x
CFLAGS-s_conjf128-ifunc.c += -fno-builtin-conjf64x
CFLAGS-s_copysignf128-ifunc.c += -fno-builtin-copysignf64x
CFLAGS-s_cosf128-ifunc.c += -fno-builtin-cosf64x
CFLAGS-w_coshf128-ifunc.c += -fno-builtin-coshf64x
CFLAGS-s_cpowf128-ifunc.c += -fno-builtin-cpowf64x
CFLAGS-s_cprojf128-ifunc.c += -fno-builtin-cprojf64x
CFLAGS-s_crealf128-ifunc.c += -fno-builtin-crealf64x
CFLAGS-s_csinf128-ifunc.c += -fno-builtin-csinf64x
CFLAGS-s_csinhf128-ifunc.c += -fno-builtin-csinhf64x
CFLAGS-s_csqrtf128-ifunc.c += -fno-builtin-csqrtf64x
CFLAGS-s_ctanf128-ifunc.c += -fno-builtin-ctanf64x
CFLAGS-s_ctanhf128-ifunc.c += -fno-builtin-ctanhf64x
CFLAGS-s_daddf128-ifunc.c += -fno-builtin-f64addf64x
CFLAGS-s_ddivf128-ifunc.c += -fno-builtin-f64divf64x
CFLAGS-s_dfmaf128-ifunc.c += -fno-builtin-f64fmaf64x
CFLAGS-s_dmulf128-ifunc.c += -fno-builtin-f64mulf64x
CFLAGS-s_dsqrtf128-ifunc.c += -fno-builtin-f64sqrtf64x
CFLAGS-s_dsubf128-ifunc.c += -fno-builtin-f64subf64x
CFLAGS-s_erff128-ifunc.c += -fno-builtin-erff64x
CFLAGS-s_erfcf128-ifunc.c += -fno-builtin-erfcf64x
CFLAGS-e_expf128-ifunc.c += -fno-builtin-expf64x
CFLAGS-w_exp10f128-ifunc.c += -fno-builtin-exp10f64x
CFLAGS-e_exp2f128-ifunc.c += -fno-builtin-exp2f64x
CFLAGS-s_expm1f128-ifunc.c += -fno-builtin-expm1f64x
CFLAGS-s_fabsf128-ifunc.c += -fno-builtin-fabsf64x
CFLAGS-s_faddf128-ifunc.c += -fno-builtin-f32addf64x
CFLAGS-s_fdimf128-ifunc.c += -fno-builtin-fdimf64x
CFLAGS-s_fdivf128-ifunc.c += -fno-builtin-f32divf64x
CFLAGS-s_ffmaf128-ifunc.c += -fno-builtin-f32fmaf64x
CFLAGS-s_floorf128-ifunc.c += -fno-builtin-floorf64x
CFLAGS-s_fmaf128-ifunc.c += -fno-builtin-fmaf64x
CFLAGS-s_fmaxf128-ifunc.c += -fno-builtin-fmaxf64x
CFLAGS-s_fmaximumf128-ifunc.c += -fno-builtin-fmaximumf64x
CFLAGS-s_fmaximum_magf128-ifunc.c += -fno-builtin-fmaximum_magf64x
CFLAGS-s_fmaximum_mag_numf128-ifunc.c += -fno-builtin-fmaximum_mag_numf64x
CFLAGS-s_fmaximum_numf128-ifunc.c += -fno-builtin-fmaximum_numf64x
CFLAGS-s_fmaxmagf128-ifunc.c += -fno-builtin-fmaxmagf64x
CFLAGS-s_fminf128-ifunc.c += -fno-builtin-fminf64x
CFLAGS-s_fminimumf128-ifunc.c += -fno-builtin-fminimumf64x
CFLAGS-s_fminimum_magf128-ifunc.c += -fno-builtin-fminimum_magf64x
CFLAGS-s_fminimum_mag_numf128-ifunc.c += -fno-builtin-fminimum_mag_numf64x
CFLAGS-s_fminimum_numf128-ifunc.c += -fno-builtin-fminimum_numf64x
CFLAGS-s_fminmagf128-ifunc.c += -fno-builtin-fminmagf64x
CFLAGS-w_fmodf128-ifunc.c += -fno-builtin-fmodf64x
CFLAGS-s_fmulf128-ifunc.c += -fno-builtin-f32mulf64x
CFLAGS-s_frexpf128-ifunc.c += -fno-builtin-frexpf64x
CFLAGS-s_fromfpf128-ifunc.c += -fno-builtin-fromfpf64x
CFLAGS-s_fromfpxf128-ifunc.c += -fno-builtin-fromfpxf64x
CFLAGS-s_fsqrtf128-ifunc.c += -fno-builtin-f32sqrtf64x
CFLAGS-s_fsubf128-ifunc.c += -fno-builtin-f32subf64x
CFLAGS-s_getpayloadf128-ifunc.c += -fno-builtin-getpayloadf64x
CFLAGS-w_hypotf128-ifunc.c += -fno-builtin-hypotf64x
CFLAGS-w_ilogbf128-ifunc.c += -fno-builtin-ilogbf64x
CFLAGS-w_j0f128-ifunc.c += -fno-builtin-j0f64x
CFLAGS-w_j1f128-ifunc.c += -fno-builtin-j1f64x
CFLAGS-w_jnf128-ifunc.c += -fno-builtin-jnf64x
CFLAGS-s_ldexpf128-ifunc.c += -fno-builtin-ldexpf64x
CFLAGS-w_lgammaf128-ifunc.c += -fno-builtin-lgammaf64x
CFLAGS-w_lgammaf128_r-ifunc.c += -fno-builtin-lgammaf64x_r
CFLAGS-w_llogbf128-ifunc.c += -fno-builtin-llogbf64x
CFLAGS-s_llrintf128-ifunc.c += -fno-builtin-llrintf64x
CFLAGS-s_llroundf128-ifunc.c += -fno-builtin-llroundf64x
CFLAGS-e_logf128-ifunc.c += -fno-builtin-logf64x
CFLAGS-w_log10f128-ifunc.c += -fno-builtin-log10f64x
CFLAGS-w_log1pf128-ifunc.c += -fno-builtin-log1pf64x
CFLAGS-e_log2f128-ifunc.c += -fno-builtin-log2f64x
CFLAGS-s_logbf128-ifunc.c += -fno-builtin-logbf64x
CFLAGS-s_lrintf128-ifunc.c += -fno-builtin-lrintf64x
CFLAGS-s_lroundf128-ifunc.c += -fno-builtin-lroundf64x
CFLAGS-s_modff128-ifunc.c += -fno-builtin-modff64x
CFLAGS-s_nanf128-ifunc.c += -fno-builtin-nanf64x
CFLAGS-s_nearbyintf128-ifunc.c += -fno-builtin-nearbyintf64x
CFLAGS-s_nextafterf128-ifunc.c += -fno-builtin-nextafterf64x
CFLAGS-s_nextdownf128-ifunc.c += -fno-builtin-nextdownf64x
CFLAGS-s_nextupf128-ifunc.c += -fno-builtin-nextupf64x
CFLAGS-e_powf128-ifunc.c += -fno-builtin-powf64x
CFLAGS-w_remainderf128-ifunc.c += -fno-builtin-remainderf64x
CFLAGS-s_remquof128-ifunc.c += -fno-builtin-remquof64x
CFLAGS-s_rintf128-ifunc.c += -fno-builtin-rintf64x
CFLAGS-s_roundf128-ifunc.c += -fno-builtin-roundf64x
CFLAGS-s_roundevenf128-ifunc.c += -fno-builtin-roundevenf64x
CFLAGS-w_scalblnf128-ifunc.c += -fno-builtin-scalblnf64x
CFLAGS-s_scalbnf128-ifunc.c += -fno-builtin-scalbnf64x
CFLAGS-s_setpayloadf128-ifunc.c += -fno-builtin-setpayloadf64x
CFLAGS-s_setpayloadsigf128-ifunc.c += -fno-builtin-setpayloadsigf64x
CFLAGS-s_sinf128-ifunc.c += -fno-builtin-sinf64x
CFLAGS-s_sincosf128-ifunc.c += -fno-builtin-sincosf64x
CFLAGS-w_sinhf128-ifunc.c += -fno-builtin-sinhf64x
CFLAGS-w_sqrtf128-ifunc.c += -fno-builtin-sqrtf64x
CFLAGS-s_tanf128-ifunc.c += -fno-builtin-tanf64x
CFLAGS-s_tanhf128-ifunc.c += -fno-builtin-tanhf64x
CFLAGS-w_tgammaf128-ifunc.c += -fno-builtin-tgammaf64x
CFLAGS-s_totalorderf128-ifunc.c += -fno-builtin-totalorderf64x
CFLAGS-s_totalordermagf128-ifunc.c += -fno-builtin-totalordermagf64x
CFLAGS-s_truncf128-ifunc.c += -fno-builtin-truncf64x
CFLAGS-s_ufromfpf128-ifunc.c += -fno-builtin-ufromfpf64x
CFLAGS-s_ufromfpxf128-ifunc.c += -fno-builtin-ufromfpxf64x
CFLAGS-s_y0f128-ifunc.c += -fno-builtin-y0f64x
CFLAGS-s_y1f128-ifunc.c += -fno-builtin-y1f64x
CFLAGS-s_ynf128-ifunc.c += -fno-builtin-ynf64x

endif # do_f128_multiarch

libm-sysdep_routines += e_log-ppc64

ifeq ($(mcpu-power10), yes)
libm-sysdep_routines += e_log-power10
CFLAGS-e_log-power10.c += -mcpu=power10
endif

endif
